﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SDS.SPHealthAnalyzerRules.Delegation.Helpers
{

    public static class AD_SPN
    {
        [System.Diagnostics.DebuggerDisplay("Class = [{ClassName}], Hostname = [{Hostname}], Account = [{Account}]")]
        public struct SPN
        {
            public string ClassName { get; set; }
            public string Hostname { get; set; }
            public string Account { get; set; }
        }

        public static IEnumerable<SPN> Find(string ClassName, string HostName, string AccountName)
        {
            List<SPN> outval = new List<SPN>();

            System.DirectoryServices.DirectorySearcher ds = new System.DirectoryServices.DirectorySearcher();
            ds.Filter = GetDirectorySearcherFilter(ClassName, HostName, AccountName);
            ds.PropertiesToLoad.AddRange("dnsHostName,distinguishedName,servicePrincipalName,objectClass,samAccountName".Split(','));
            System.DirectoryServices.SearchResultCollection res = ds.FindAll();

            foreach (var obj in res.Cast<System.DirectoryServices.SearchResult>())
            {
                foreach (string spn in obj.Properties["servicePrincipalName"])
                {
                    string spnClassName = spn.Split('/')[0];
                    string spnHostname = spn.Split('/')[1];
                    string spnAccount = obj.Properties["samAccountName"][0] as string;

                    // since the user may have many SPNs, we now need to reconsider the filter, before providing results
                    if ((String.IsNullOrEmpty(ClassName) || spnClassName.ToLower() == ClassName.ToLower()) &&
                        (String.IsNullOrEmpty(HostName) || spnHostname.ToLower().StartsWith(HostName.ToLower())) &&
                        (String.IsNullOrEmpty(AccountName) || spnAccount.ToLower() == AccountName.ToLower()))
                        outval.Add(new SPN() { ClassName = spnClassName, Hostname = spnHostname, Account = spnAccount });
                }
            }

            return outval;
        } // static IEnumerable<SPN> Find(...)

        public static string GetDirectorySearcherFilter(string ClassName, string HostName, string AccountName)
        {
            // build an SPN using ClassName and/or Hostname
            string SPN = String.Format("{0}{1}{2}",
                                       ClassName,
                                       String.IsNullOrEmpty(ClassName) || String.IsNullOrEmpty(HostName) ? "" : "/",
                                       HostName);

            // set the ADSI filter for the SPN
            string dsFilter_SPN = String.IsNullOrEmpty(SPN) ? "" : String.Format("(servicePrincipalName=*{0}*)", SPN);

            // set the ADSI filter for the account name
            string dsFilter_Account = String.IsNullOrEmpty(AccountName) ? "" : String.Format("(sAMAccountName={0})", AccountName);

            // check whether using SPN and/or account name filters
            bool dsFilter_SPN_And_Account = !String.IsNullOrEmpty(SPN) && !String.IsNullOrEmpty(AccountName);

            // build the final ADSI filter string
            string dsFilter = String.Format("{0}{1}{2}{3}",
                                            dsFilter_SPN_And_Account ? "(&" : "",
                                            dsFilter_Account,
                                            dsFilter_SPN,
                                            dsFilter_SPN_And_Account ? ")" : "");

            return dsFilter;
        } // static string GetDirectorySearcheFilter(...)
    } // class AD_SPN

} // namespace
